#include <vtkForceDirectedLayoutStrategy.h>
#include <vtkGraphLayoutView.h>
#include <vtkMutableUndirectedGraph.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>

#include <vtkArcSource.h>
#include <vtkPolyDataMapper.h>
#include "vtkPolygon.h"
#include "vtkProperty.h"

#include "vtkLookupTable.h"
#include "vtkMinimalStandardRandomSequence.h"
#include "vtkCellData.h"
#include "vtkFloatArray.h"
#include "vtkTexture.h"

#include "vtkGlyph3DMapper.h"
#include "vtkSphereSource.h"

#include "vtkInteractorStyleTrackballCamera.h"
#include "vtkColorTransferFunction.h"

#include <array>
#include <vector>


vtkSmartPointer<vtkLookupTable> GetDivergingLut();


int main(int, char*[]) {
    vtkNew<vtkRenderer> renderer;
    vtkNew<vtkRenderWindow> renderWindow;
    renderWindow->SetWindowName("RegularPolygonSource");
    renderWindow->AddRenderer(renderer);
    vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
//    renderWindowInteractor->SetInteractorStyle(vtkNew<vtkInteractorStyleTrackballCamera>)
    renderWindowInteractor->SetRenderWindow(renderWindow);


    vtkNew<vtkNamedColors> colors;


    const int RowCount = 36;
    const int ColCount = 40;
    const double RowDegree = vtkMath::Pi() * 2 / RowCount;
    const double Radius = 500;
    const int AreaAvgRadius = Radius / ColCount;
    const int ArcSegmentCount = 1;
    double ArcSegmentDegree = RowDegree / ArcSegmentCount;

    vtkNew<vtkCellArray> allPolygons;
    vtkNew<vtkPoints> allPoints;
    vtkNew<vtkPolyData> polygonPolyData;

//    for (int i = 0; i < RowCount; ++i) {
//
//        double degree = RowDegree * i;
//
//        for (int j = 0; j < ColCount; ++j) {
//
//            vtkNew<vtkPolygon> polygon;
//            polygon->GetPointIds()->SetNumberOfIds((ArcSegmentCount + 1) * 2);
//            vtkIdType numberOfPoints = allPoints->GetNumberOfPoints();
//
//            double radius0 = j * AreaAvgRadius;
//            double radius1 = (j + 1) * AreaAvgRadius;
//
//            for (int k = 0; k < ArcSegmentCount + 1; ++k) {
//                double d0 = degree + (ArcSegmentDegree) * k;
//                double x0 = cos(d0) * radius0;
//                double y0 = sin(d0) * radius0;
//                allPoints->InsertNextPoint(x0, y0, 0.0);
//
//                double d1 = degree + (ArcSegmentDegree) * k;
//                double x1 = cos(d1) * radius1;
//                double y1 = sin(d1) * radius1;
//                allPoints->InsertNextPoint(x1, y1, 0.0);
//
//                polygon->GetPointIds()->SetId(k, numberOfPoints + (ArcSegmentCount - k));
//                polygon->GetPointIds()->SetId(k + ArcSegmentCount + 1, numberOfPoints + ArcSegmentCount + 1 + k);
//            }
//
//            allPolygons->InsertNextCell(polygon);
//        }
//    }

//    polygonPolyData->SetPoints(allPoints);
//    polygonPolyData->SetPolys(allPolygons);

//    vtkNew<vtkPolyDataMapper> mapper;
//    mapper->SetInputData(polygonPolyData);

    for (int i = 0; i < 100; ++i) {
        allPoints->InsertNextPoint(i, 0, 0);
    }
    polygonPolyData->SetPoints(allPoints);

    vtkNew<vtkSphereSource> sphere;
    sphere->SetRadius(2);
    vtkNew<vtkGlyph3DMapper> mapper;
    mapper->SetInputData(polygonPolyData);
    mapper->SetSourceConnection(sphere->GetOutputPort());
    mapper->ScalarVisibilityOff();
    mapper->ScalingOff();



    vtkNew<vtkFloatArray> cellData;
    for (int i = 0; i < RowCount * ColCount; i++)
    {
        cellData->InsertNextValue(i + 1);
    }

    polygonPolyData->GetCellData()->SetScalars(cellData);

    mapper->SetScalarRange(0, 75);
    mapper->ScalarVisibilityOn();
    mapper->SetLookupTable(GetDivergingLut());


    vtkNew<vtkActor> actor;
    actor->SetMapper(mapper);
//    actor->GetProperty()->EdgeVisibilityOn();
    renderer->AddActor(actor);


    renderWindow->Render();
    renderWindowInteractor->Initialize();
    renderWindowInteractor->Start();

    //    renderWindow->GetRenderers()[0]
//    vtkActorCollection* actors = renderer->GetActors();
//    vtkSmartPointer<vtkPolyData> ringActorData;
//
//    if (renderer->GetActors()->GetNumberOfItems() > 0) {
//        auto aaa = renderer->GetActors()->GetItemAsObject(0);
//
//        vtkSmartPointer<vtkActor> actt = static_cast<vtkActor*>(aaa);
//        vtkSmartPointer<vtkActor> actt2 = static_cast<vtkActor*>(aaa);
//        vtkSmartPointer<vtkActor> actt3 = static_cast<vtkActor*>(aaa);
//
//        ringActorData = static_cast<vtkPolyData*>(actt->GetMapper()->GetInput());
//        vtkSmartPointer<vtkPolyData> ringActorData2 = static_cast<vtkPolyData*>(actt->GetMapper()->GetInput());
//        vtkSmartPointer<vtkPolyData> ringActorData3 = static_cast<vtkPolyData*>(actt->GetMapper()->GetInput());
//    }


//    vtkNew<vtkUnsignedCharArray> cellData;
//    cellData->SetNumberOfComponents(3);
//    cellData->SetNumberOfTuples(polygonPolyData->GetNumberOfCells());
//
//    vtkNew<vtkMinimalStandardRandomSequence> randomSequence;
//    randomSequence->SetSeed(8775070);
//    auto min_r = 64.0;
//    auto max_r = 255.0;
//    for (int i = 0; i < polygonPolyData->GetNumberOfCells(); i++)
//    {
//        double rgb[3];
//        for (auto j = 0; j < 3; ++j)
//        {
//            rgb[j] = randomSequence->GetRangeValue(min_r, max_r);
//            randomSequence->Next();
//        }
//        cellData->InsertTuple(i, rgb);
//    }


//    polygonPolyData->GetCellData()->SetScalars(cellData);
//    actor->Modified();
//    renderWindow->Render();
//    renderWindowInteractor->Render();



    return EXIT_SUCCESS;
}



vtkSmartPointer<vtkLookupTable> GetDivergingLut()
{

//    vtkNew<vtkColorTransferFunction> ctf;
//    ctf->SetColorSpaceToDiverging();
////    ctf->AddRGBPoint(0.0, 0.230, 0.299, 0.754);
////    ctf->AddRGBPoint(0.5, 0.865, 0.865, 0.865);
////    ctf->AddRGBPoint(1.0, 0.706, 0.016, 0.150);
//
//    ctf->AddRGBPoint(0, 92, 201, 250);
//    ctf->AddRGBPoint(1.0, 117, 20, 114);


    vtkNew<vtkColorTransferFunction> colorTransferFunction;
    colorTransferFunction->SetColorSpaceToRGB();
    std::vector<std::array<double, 3>> colorList;
    colorList.push_back({92, 201, 250});
    colorList.push_back({42, 100, 246});
    colorList.push_back({17, 50, 196});
    colorList.push_back({117, 251, 122});
    colorList.push_back({102, 201, 113});
    colorList.push_back({67, 151, 42});
    colorList.push_back({254, 255, 127});
    colorList.push_back({247, 206, 85});
    colorList.push_back({241, 158, 56});
    colorList.push_back({236, 112, 107});
    colorList.push_back({234, 72, 63});
    colorList.push_back({186, 38, 26});
    colorList.push_back({234, 51, 247});
    colorList.push_back({188, 39, 198});
    colorList.push_back({117, 20, 124});

    double rangeMin = 0;
    double rangeMax = 75;
    int colorCount = colorList.size();
    double rangeSection = (rangeMax - rangeMin) / colorCount;
    for (int i = 0; i < colorCount; ++i) {
        std::array<double, 3> color = colorList[i];
        colorTransferFunction->AddRGBPoint(rangeSection * i, color[0] / 255.0, color[1] / 255.0, color[2] / 255.0);
        if (i < colorCount - 1) {
            std::array<double, 3> color1 = colorList[i + 1];
            colorTransferFunction->AddRGBPoint(rangeSection * (i + 1) - 0.01, color1[0] / 255.0, color1[1] / 255.0, color1[2] / 255.0);
        }
    }

    colorTransferFunction->Build();

    auto tableSize = 15;
    vtkNew<vtkLookupTable> lut;
    lut->SetVectorModeToRGBColors();
    lut->SetNumberOfTableValues(tableSize);
    lut->SetTableRange(0, 75);
    lut->Build();

    for (auto i = 0; i < lut->GetNumberOfColors(); ++i)
    {
        std::array<double, 3> rgb;
        colorTransferFunction->GetColor(static_cast<double>(i) / lut->GetNumberOfColors(),
                                        rgb.data());
        colorTransferFunction->GetColor(static_cast<double>(i) * 5, rgb.data());

//        std::cout << i << ":" << rgb[0] << " - " << rgb[1] << " - " << rgb[2] << std::endl;

//        std::array<double, 4> rgb;
//        if (i == 0) {
//            rgb = {1, 0, 0, 1};
//        }else {
//            rgb = {0, 1, 0, 1};
//        }
//
//        std::cout << i << ":" << rgb.data()[0] << " - " << rgb.data()[1] << " - " << rgb.data()[2] << std::endl;
//
//        lut->SetTableValue(static_cast<vtkIdType>(i), rgb.data());

        std::array<double, 4> rgba{0.0, 0.0, 0.0, 1.0};
        std::copy(std::begin(rgb), std::end(rgb), std::begin(rgba));
        lut->SetTableValue(static_cast<vtkIdType>(i), rgba.data());
    }

    return lut;
}